package config

import (
	"fmt"
	"hash/fnv"

	"github.com/BurntSushi/toml"
)

type Instance struct { // TODO: rename
	Name    string
	Idx     int
	Address string
}

type Config struct {
	DistributeInstances []Instance
}

// ParseFile parses the config and returns it upon success
func ParseFile(filename string) (Config, error) {
	var c Config
	if _, err := toml.DecodeFile(filename, &c); err != nil {
		return Config{}, err // no config
	}

	return c, nil
}

type Instances struct { // TODO: rename
	Count  int
	CurIdx int
	Addrs  map[int]string
}

// ParseInstances converts and verifies the list of instances
// specified in the config into a form that can be used
// for routing
func ParseInstances(instnaces []Instance, cur_inst_name string) (*Instances, error) {
	inst_count := len(instnaces)
	inst_index := -1
	addrs := make(map[int]string)

	for _, inst := range instnaces {
		if _, ok := addrs[inst.Idx]; ok {
			return nil, fmt.Errorf("duplicate instance index: %d", inst.Idx)
		}

		addrs[inst.Idx] = inst.Address
		if inst.Name == cur_inst_name {
			inst_index = inst.Idx
		}
	}

	for i := 0; i < inst_count; i++ {
		if _, ok := addrs[i]; !ok {
			return nil, fmt.Errorf("distribute kv database instance %d is not found", i)
		}
	}

	if inst_index < 0 {
		return nil, fmt.Errorf("distribute kv database instance %q not found", cur_inst_name)
	}

	return &Instances{
		Addrs:  addrs,
		Count:  inst_count,
		CurIdx: inst_index,
	}, nil
}

// Index returns the instance number for the corresponding key
func (in *Instances) Index(key string) int {
	h := fnv.New64()
	h.Write([]byte(key))
	return int(h.Sum64() % uint64(in.Count))
}
